﻿using CoachingOrganizer.Logic.Models.Tools.EmotionsPack;
using CoachingOrganizer.WinPhone.UITools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;

namespace CoachingOrganizer.WinPhone.ViewModels.Tools.EmotionsPack
{
    public class EmotionsPackViewModel : ToolViewModelBase
    {
        private readonly EmotionsPackModel _model;
        private readonly Windows.Media.Capture.MediaCapture _traceEmotionSource;
        private readonly EventWaitHandle _waitTraceEmotionSourceInit = new EventWaitHandle(true, EventResetMode.AutoReset);
        private string _newTraceItemName;
        private string _tracedEmotionName;
        private object _emotionNames;

        public string NewTraceItemName
        {
            get { return _newTraceItemName; }
            set { _newTraceItemName = value; }
        }

        public string TracedEmotionName
        {
            get { return _tracedEmotionName; }
            set
            {
                if (_tracedEmotionName != value)
                {
                    _tracedEmotionName = value;
                    if (!string.IsNullOrWhiteSpace(value))
                        _model.SetSelectedEmotionByName(value);
                    OnPropertyChanged(() => TracedEmotionName);
                }
            }
        }

        public object EmotionNames
        {
            get { return _emotionNames; }
        }

        public Windows.Media.Capture.MediaCapture TraceEmotionSource
        {
            get { return _traceEmotionSource; }
        }

        public IEnumerable<EmotionTraceItemViewModel> TraceItems
        {
            get { return _model.EnumerateEmotionTraceItems().Select(m => new EmotionTraceItemViewModel(m)); }
        }

        public ICommand GoDetailsCommand
        {
            get { return GetCommand(() => GoDetailsCommand, () => UIHelper.GoToPage(this, typeof(CoachingOrganizer.WinPhone.Pages.Tools.EmotionsPack.EmotionsPackPage))); }
        }

        public ICommand SaveEmotionTraceCommand
        {
            get { return GetCommand(() => SaveEmotionTraceCommand, () => SaveEmotionTrace()); }
        }

        public EmotionsPackViewModel(EmotionsPackModel model)
            : base(model)
        {
            _model = model;
            model.EmotionTraceItemsCollectionChanged += Model_EmotionTraceItemsCollectionChanged;
            _traceEmotionSource = new Windows.Media.Capture.MediaCapture();
            InitModel();
        }

        public async Task InitTraceEmotionPreview()
        {
            if (!_waitTraceEmotionSourceInit.WaitOne(1))
                return;
            await _traceEmotionSource.InitializeAsync(new Windows.Media.Capture.MediaCaptureInitializationSettings
            {
                StreamingCaptureMode = Windows.Media.Capture.StreamingCaptureMode.Video,
                PhotoCaptureSource = Windows.Media.Capture.PhotoCaptureSource.VideoPreview
            });
        }

        public async Task BeginTraceEmotionPreview()
        {
            await _traceEmotionSource.StartPreviewAsync();
        }

        public async Task EndTraceEmotionPreview()
        {
            await _traceEmotionSource.StopPreviewAsync();
        }

        private async void InitModel()
        {
            using (CancellationTokenSource cancellation = new CancellationTokenSource())
                await _model.LoadTraceItemsAsync(cancellation.Token);
            await LoadEmotionNames();
        }

        private async Task LoadEmotionNames()
        {
            Windows.Storage.StorageFile namesFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///strings/emotionNames.xml"));
            string strContent = string.Empty;
            using (Windows.Storage.Streams.IRandomAccessStreamWithContentType namesFileStream = await namesFile.OpenReadAsync())
            {
                byte[] contentBytes = new byte[namesFileStream.Size];
                await namesFileStream.ReadAsync(contentBytes.AsBuffer(), (uint)contentBytes.Length, Windows.Storage.Streams.InputStreamOptions.None);
                strContent = Encoding.UTF8.GetString(contentBytes, 3, contentBytes.Length - 3);
            }
            System.Xml.Linq.XElement contentElement = System.Xml.Linq.XElement.Parse(strContent);
            _emotionNames = contentElement.Elements().SelectMany(e => e.Elements().Select(se => new { Key = e.Attributes().First().Value, Values = se.Value })).GroupBy(e => e.Key, e => e.Values);
            OnPropertyChanged(() => EmotionNames);
        }

        private async void SaveEmotionTrace()
        {
            EmotionTraceModel selectedEmotion = _model.SelectedEmotion;
            if (selectedEmotion == null || string.IsNullOrWhiteSpace(_newTraceItemName))
                return;
            byte[] pictureBytes = await TakePicture();
            await selectedEmotion.AddNewTraceItem(_newTraceItemName, pictureBytes);
        }

        private async Task<byte[]> TakePicture()
        {
            Windows.Media.MediaProperties.ImageEncodingProperties pictureFormat = Windows.Media.MediaProperties.ImageEncodingProperties.CreatePng();
            using (Windows.Storage.Streams.InMemoryRandomAccessStream pictureStream = new Windows.Storage.Streams.InMemoryRandomAccessStream())
            {
                await _traceEmotionSource.CapturePhotoToStreamAsync(pictureFormat, pictureStream);
                await pictureStream.FlushAsync();
                pictureStream.Seek(0L);
                byte[] pictureBytes = new byte[pictureStream.Size];
                await pictureStream.ReadAsync(pictureBytes.AsBuffer(), (uint)pictureBytes.Length, Windows.Storage.Streams.InputStreamOptions.None);
                return pictureBytes;
            }
        }

        private void Model_EmotionTraceItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            BeginInvokeInUIThread(() => OnPropertyChanged(() => TraceItems));
        }
    }
}
